package org.qs.webservice.sign;
@SuppressWarnings("unused")
public class Base64 {
	
	private static final int BASELENGTH = 128;
	private static final int LOOKUPLENGTH = 64;
	private static final int TWENTYFOURBITGROUP = 24;
	private static final int EIGHTBIT = 8;
	private static final int SIXTEENBIT = 16;
	private static final int FOURBYTE = 4;
	private static final int SIGN = -128;
	private static final char PAD = '=';
	private static final boolean fDebug = false;
	private static final byte[] base64Alphabet = new byte[''];
	private static final char[] lookUpBase64Alphabet = new char[64];

	static {
		for (int i = 0; i < 128; i++) {
			base64Alphabet[i] = -1;
	    }
	    for (int i = 90; i >= 65; i--) {
	    	base64Alphabet[i] = ((byte)(i - 65));
	    }
	    for (int i = 122; i >= 97; i--) {
	    	base64Alphabet[i] = ((byte)(i - 97 + 26));
	    }
	
	    for (int i = 57; i >= 48; i--) {
	    	base64Alphabet[i] = ((byte)(i - 48 + 52));
	    }
	
	    base64Alphabet[43] = 62;
	    base64Alphabet[47] = 63;
	
	    for (int i = 0; i <= 25; i++) {
	    	lookUpBase64Alphabet[i] = ((char)(65 + i));
	    }
	
	    int i = 26; for (int j = 0; i <= 51; j++) {
	    	lookUpBase64Alphabet[i] = ((char)(97 + j));
	
	    	i++;
	    }
	
	    i = 52; for (int j = 0; i <= 61; j++) {
	    	lookUpBase64Alphabet[i] = ((char)(48 + j));
	
	    	i++;
	    }
	
	    lookUpBase64Alphabet[62] = '+';
	    lookUpBase64Alphabet[63] = '/';
	}
	
	private static boolean isWhiteSpace(char octect){
		return (octect == ' ') || (octect == '\r') || (octect == '\n') || (octect == '\t');
	}
	
	private static boolean isPad(char octect) {
		return octect == '=';
	}
	
	private static boolean isData(char octect) {
		return (octect < '') && (base64Alphabet[octect] != -1);
	}
	
	public static String encode(byte[] binaryData){
		if (binaryData == null) {
			return null;
		}
	
		int lengthDataBits = binaryData.length * 8;
		if (lengthDataBits == 0) {
			return "";
	}
	
	int fewerThan24bits = lengthDataBits % 24;
	int numberTriplets = lengthDataBits / 24;
	int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets;
	char[] encodedData = null;
	
	encodedData = new char[numberQuartet * 4];
	
	byte k = 0; byte l = 0; byte b1 = 0; byte b2 = 0; byte b3 = 0;
	
	int encodedIndex = 0;
	int dataIndex = 0;
	
	for (int i = 0; i < numberTriplets; i++) {
		b1 = binaryData[(dataIndex++)];
		b2 = binaryData[(dataIndex++)];
		b3 = binaryData[(dataIndex++)];
	
		l = (byte)(b2 & 0xF);
		k = (byte)(b1 & 0x3);
	
		byte val1 = (b1 & 0xFFFFFF80) == 0 ? (byte)(b1 >> 2) : (byte)(b1 >> 2 ^ 0xC0);
		byte val2 = (b2 & 0xFFFFFF80) == 0 ? (byte)(b2 >> 4) : (byte)(b2 >> 4 ^ 0xF0);
	    byte val3 = (b3 & 0xFFFFFF80) == 0 ? (byte)(b3 >> 6) : (byte)(b3 >> 6 ^ 0xFC);
	
	    encodedData[(encodedIndex++)] = lookUpBase64Alphabet[val1];
	    encodedData[(encodedIndex++)] = lookUpBase64Alphabet[(val2 | k << 4)];
	    encodedData[(encodedIndex++)] = lookUpBase64Alphabet[(l << 2 | val3)];
	    encodedData[(encodedIndex++)] = lookUpBase64Alphabet[(b3 & 0x3F)];
	}
	
	if (fewerThan24bits == 8) {
	  b1 = binaryData[dataIndex];
	  k = (byte)(b1 & 0x3);
	
	  byte val1 = (b1 & 0xFFFFFF80) == 0 ? (byte)(b1 >> 2) : (byte)(b1 >> 2 ^ 0xC0);
	  encodedData[(encodedIndex++)] = lookUpBase64Alphabet[val1];
	  encodedData[(encodedIndex++)] = lookUpBase64Alphabet[(k << 4)];
	  encodedData[(encodedIndex++)] = '=';
	  encodedData[(encodedIndex++)] = '=';
	} else if (fewerThan24bits == 16) {
	  b1 = binaryData[dataIndex];
	  b2 = binaryData[(dataIndex + 1)];
	  l = (byte)(b2 & 0xF);
	  k = (byte)(b1 & 0x3);
	
	  byte val1 = (b1 & 0xFFFFFF80) == 0 ? (byte)(b1 >> 2) : (byte)(b1 >> 2 ^ 0xC0);
	  byte val2 = (b2 & 0xFFFFFF80) == 0 ? (byte)(b2 >> 4) : (byte)(b2 >> 4 ^ 0xF0);
	
	  encodedData[(encodedIndex++)] = lookUpBase64Alphabet[val1];
	  encodedData[(encodedIndex++)] = lookUpBase64Alphabet[(val2 | k << 4)];
	  encodedData[(encodedIndex++)] = lookUpBase64Alphabet[(l << 2)];
	  encodedData[(encodedIndex++)] = '=';
	    }
	
	    return new String(encodedData);
	  }
	
	  public static byte[] decode(String encoded)
	  {
	    if (encoded == null) {
	      return null;
	    }
	
	    char[] base64Data = encoded.toCharArray();
	
	    int len = removeWhiteSpace(base64Data);
	
	    if (len % 4 != 0) {
	      return null;
	    }
	
	    int numberQuadruple = len / 4;
	
	    if (numberQuadruple == 0) {
	      return new byte[0];
	    }
	
	    byte[] decodedData = null;
	    byte b1 = 0; byte b2 = 0; byte b3 = 0; byte b4 = 0;
	    char d1 = '\000'; char d2 = '\000'; char d3 = '\000'; char d4 = '\000';
	
	    int i = 0;
	    int encodedIndex = 0;
	    int dataIndex = 0;
	    decodedData = new byte[numberQuadruple * 3];
	
	    for (; i < numberQuadruple - 1; i++)
	    {
	      if ((!isData(d1 = base64Data[(dataIndex++)])) || (!isData(d2 = base64Data[(dataIndex++)])) || 
	        (!isData(d3 = base64Data[(dataIndex++)])) || 
	        (!isData(d4 = base64Data[(dataIndex++)]))) {
	        return null;
	      }
	
	      b1 = base64Alphabet[d1];
	      b2 = base64Alphabet[d2];
	      b3 = base64Alphabet[d3];
	      b4 = base64Alphabet[d4];
	
	      decodedData[(encodedIndex++)] = ((byte)(b1 << 2 | b2 >> 4));
	      decodedData[(encodedIndex++)] = ((byte)((b2 & 0xF) << 4 | b3 >> 2 & 0xF));
	      decodedData[(encodedIndex++)] = ((byte)(b3 << 6 | b4));
	    }
	
	    if ((!isData(d1 = base64Data[(dataIndex++)])) || (!isData(d2 = base64Data[(dataIndex++)]))) {
	      return null;
	    }
	
	    b1 = base64Alphabet[d1];
	    b2 = base64Alphabet[d2];
	
	    d3 = base64Data[(dataIndex++)];
	    d4 = base64Data[(dataIndex++)];
	    if ((!isData(d3)) || (!isData(d4))) {
	      if ((isPad(d3)) && (isPad(d4))) {
	        if ((b2 & 0xF) != 0)
	        {
	          return null;
	        }
	        byte[] tmp = new byte[i * 3 + 1];
	        System.arraycopy(decodedData, 0, tmp, 0, i * 3);
	        tmp[encodedIndex] = ((byte)(b1 << 2 | b2 >> 4));
	        return tmp;
	      }if ((!isPad(d3)) && (isPad(d4))) {
	        b3 = base64Alphabet[d3];
	        if ((b3 & 0x3) != 0)
	        {
	          return null;
	        }
	        byte[] tmp = new byte[i * 3 + 2];
	        System.arraycopy(decodedData, 0, tmp, 0, i * 3);
	        tmp[(encodedIndex++)] = ((byte)(b1 << 2 | b2 >> 4));
	        tmp[encodedIndex] = ((byte)((b2 & 0xF) << 4 | b3 >> 2 & 0xF));
	        return tmp;
	      }
	      return null;
	    }
	
	    b3 = base64Alphabet[d3];
	    b4 = base64Alphabet[d4];
	    decodedData[(encodedIndex++)] = ((byte)(b1 << 2 | b2 >> 4));
	    decodedData[(encodedIndex++)] = ((byte)((b2 & 0xF) << 4 | b3 >> 2 & 0xF));
	    decodedData[(encodedIndex++)] = ((byte)(b3 << 6 | b4));
	
	    return decodedData;
	  }
	
	  private static int removeWhiteSpace(char[] data)
	  {
	    if (data == null) {
	      return 0;
	    }
	
	    int newSize = 0;
	    int len = data.length;
	    for (int i = 0; i < len; i++) {
	      if (!isWhiteSpace(data[i])) {
	        data[(newSize++)] = data[i];
	      }
	    }
	    return newSize;
	  }
	}